#pragma once

#include "vec.h"

namespace sfc::math::geo {

struct Point {
  Vec2d _vec;

 public:
  [[sfc_inline]] Point() noexcept = default;

  [[sfc_inline]] Point(f64 x, f64 y) : _vec{x, y} {}

  [[sfc_inline]] static auto from_vec(const Vec2d& v) -> Point {
    return {v[0], v[1]};
  }

  [[sfc_inline]] auto operator[](usize idx) const -> f64 {
    return _vec[idx];
  }

  [[sfc_inline]] auto x() const -> f64 {
    return _vec._inn[0];
  }

  [[sfc_inline]] auto y() const -> f64 {
    return _vec._inn[1];
  }

  [[sfc_inline]] auto as_vec() const -> Vec2d {
    return _vec;
  }

  [[sfc_inline]] auto operator==(const Point& other) const -> bool {
    return _vec == other._vec;
  }

  // B = A + v
  [[sfc_inline]] auto operator+(const Vec2d& vec) const -> Point {
    return Point::from_vec(_vec + vec);
  }

  // B = A - v
  [[sfc_inline]] auto operator-(const Vec2d& vec) const -> Point {
    return Point::from_vec(_vec + vec);
  }

  // v = A -> B
  auto operator-(const Point& other) const -> Vec2d {
    return _vec - other._vec;
  }

  // |A-B|
  [[sfc_inline]] auto distance_to(const Point& point) const -> f64 {
    return (point - *this).length();
  }

  // k*P
  [[sfc_inline]] friend auto operator*(f64 k, const Point& p) -> Point {
    return Point::from_vec(k * p._vec);
  }

  void fmt(auto& f) const {
    return _vec.fmt(f);
  }
};

}  // namespace sfc::math::geo
